home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989-1999 Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either expressed or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
-
- Allocation of Input and
- Other System Resources
-
- by Bob Burns
-
-
- In most system designs there is a trade-off between ease of use and
- performance. The Amiga is no exception. Historically, high performance
- applications have resorted to taking over the machine in order to get direct
- access to system resources. This is something we would like to avoid because
- once the machine is taken over, there is no exit. The user must reboot.
- The purpose of this article is to present some techniques that let games
- and other special applications take over those portions of the system that
- they need, yet gracefully return them when no longer needed.
-
-
- Input Resources
- ---------------
-
- The Input Task
-
- A useful metaphor for describing the input task on the Amiga is the
- "food-chain". Raw input events are passed through a linked list of handlers.
- Each handler processes the input events it receives and returns a new set to
- be "consumed" by the next input handler in the chain.
-
- The primal input events are designated RAWKEY, RAWMOUSE, TIMER and DISK.
- The RAWKEY, RAWMOUSE and TIMER input events are started up the food chain by
- the input.device itself in response to its continuing IO requests to the
- keyboard, gameport, and timer devices. The DISK events are inserted into
- the chain by the DOS.
-
- The two standard consumers in the food chain are Intuition and the console
- device. Intuition in particular is prolific in the variety of new input
- events it may produce in response to a primal event. Another consumer often
- found in the food chain is a generic hotkey program. These insert themselves
- in the food chain before either Intuition or the console.
-
- The food chain is implemented as a a prioritized list, with Intuition at a
- priority of 50 and the console device at 20. For more on input events, see
- the devices/inputevents.h header.
-
-
- Input Device Commands
-
- Let's quickly review the input device commands you can use to control the
- food chain. Insertion and removal of a new consumer in the input device food
- chain is performed by the input.device commands AddHandler and RemHandler.
-
- The command WriteEvent is used to propagate an event through the input food
- chain without being on it.
-
- The commands SetThresh and SetPeriod are used to modifiy the key repeat rate.
-
- Finally, the commands SetMPort, SetMType, and SetMTrig are used to modify the
- gameport controller that is to be used for mouse input. The use of these
- commands is illustrated in the example code shown below.
-
- The joymouse.c example uses the commands to move the mouse to the second
- gameport device so that the first gameport can be used with a lightpen. This
- is useful for owners of the original model A1000 and A2000s.
-
- The joymouse.c example also shows how to change the first gameport to work
- with a joystick, or remove it from the input food chain entirely so both
- ports can be used for other purposes.
-
- You need only disable the mouse to use the gameports for your special purposes.
- You don't need to take over the whole machine. The gameport.device can then
- be used to gather data from the port, or the hardware can be read directly.
-
-
-
- Gameport Input
-
- The gameport.device contains two units, one for each gameport. The original
- Amiga design called for game controllers to be allocated to applications as
- follows:
-
- 1. Let multiple opens of gameport.device occur.
-
- 2. Follow a high level protocol for determining if the
- gameport is in use: check via AskCType for the flag
- GPCT_NOCONTROLLER. If set, then no one else is using it.
-
- There are some problems with this scheme. First, there is no protection
- between SetCType and AskCType. So two tasks can AskCType, see NO, and
- both SetCType. Second, because games often go directly to the hardware,
- the gameport.device became just a spoon-feeder to the input.device for mouse
- input.
-
- Despite these problems, the gameports can still be shared between applications
- in a system-compatible way. Neither the SetCType nor AskCType commands are
- deferred, nor do they wait and thus break a Forbid. This means you can use
- the following code to get a gameport:
-
- Forbid
- AskCType
- if(GPCT_NOCONTROLLER){
- SetCType
- owned = TRUE }
- else
- owned = FALSE
- endif
- Permit
-
- We normally try to discourage counting on this kind of side effect, but in
- this case, it's the only way. If the port is being allocated, but not for
- one of the supported controller types, then set the controller to the
- catch-all value GPCT_ALLOCATED.
-
-
-
- Joysticks
-
- To read a joystick, there are three choices. The first is to change the
- mouse port to a joystick port and capture events from the input device food
- chain as a handler. This is not recommended.
-
- The second choice is to read the joystick port directly from the hardware
- registers. It's fairly easy to do and we cannot fault folks for doing it
- this way - just make sure to allocate the gameport unit so other applications
- know you've got the port. You should also allocate the POTGO resource bits
- to acquire buttons 2 & 3.
-
- The third choice is to use the gameport device. This polls every vertical
- blank and only satisfies requests when trigger conditions are met. It's
- advantages are that the polling runs out of the contention-free ROMs, and
- when combined with certain reply port types (e.g. the direct call action),
- can be efficient for your application.
-
-
-
- Proportional Controller
-
- Unfortunately, support for proportional controllers in the gameport device
- was removed in one of the early code crunches. This occurred after support
- for Coleco-style controllers had already been removed. The example program
- propjoy.c shown below demonstrates how to use the potgo resource and some
- vblank interrupt routines to track proportional controllers.
-
-
-
- Keyboard Input
-
- The input device IO requests to the gameport can be shut down but IO requests
- to the keyboard cannot. If an application requests key events from the
- keyboard, it will probably get about half of them: every other one going to
- the input device. So, to learn about all the key states an application can
- either poll the keyboard with the ReadMatrix command, or insert itself as a
- handler in the food chain. If you use the ReadMatrix command, note that
- io_Length MUST be exactly 13.
-
-
-
-
- Other System Resources
- ----------------------
-
- Misc
-
- Whenever using serial or parallel port resources, they must be acquired from
- the misc.resource. The misc.resource oversees usage of the serial data port,
- the serial communication bits, the parallel data and handshake port, and the
- parallel communication bits. The parallel communication bits double as the
- Commodore serial bus interface bits for those who want to connect a 1541 to
- the Amiga.
-
- The serial and parallel devices both use the misc.resource. If the Exec
- device is opened and closed, the appropriate two misc resources will be
- allocated then freed. Unfortunately, if the DOS devices SER: or PAR: have
- been opened, they will open the device and thus the corresponding resource
- pair forever. For more information on this problem see the article on the
- parallel and serial resources elsewhere in this issue.
-
-
- Disk
-
- Whenever using floppy disk resources, they must be acquired from the disk
- resource. The disk resource provides both a gross and a fine unit allocation
- scheme. AllocUnit and FreeUnit are used to claim a unit for long term use,
- and GetUnit and GiveUnit are used to claim a unit for shorter periods.
-
- The trackdisk.device uses and abides by both allocation schemes. Because a
- trackdisk unit is never closed for Amiga 3.5" drives, since the file system
- keeps them open, the associated resource units will always be allocated for
- these drives. GetUnit and GiveUnit can still be used, however, by other
- applications that have not succeeded with AllocUnit.
-
- It is therefore possible to prevent the trackdisk device from using units that
- have not been mounted yet by successfully performing an AllocUnit for that
- unit. It is also possible to starve trackdisk usage by performing a GetUnit.
- The appropriate companion routine (FreeUnit or GiveUnit) should be called to
- restore the resource at the end of its use.
-
-
- CIA
-
- CIA resources not associated with the misc and disk resources are the joystick
- fire buttons, which are acquired with the appropriate gameport.device unit,
- the LED/audio filter, which is catch-as-catch-can, the memory overlay bit
- and the keyboard serial interface, which is defined to be allocated by the
- keyboard.device when it is running. The CIAB timers are available to be
- allocated and are associated with an interrupt. It is therefore allocated by
- successfully adding a vector for that interrupt with AddICRVector.
-
-
- Amiga CIA Timer Allocation
-
- CIAA (int 2)
- timerA Used for keyboard handshake
- timerB Used for uSec timer.device
- TOD Used for 60Hz timer.device
-
- CIAB (int 6)
- timerA Commodore serial bus communication, usually not used
- timerB Not used
- TOD Used for graphics.library beam counter
-
-
- By using the techniques outlined above, you can often avoid taking over the
- whole system in your high-performance applications. Allocate only the
- resources you need and return them when you are done.
-
-
- Copyright (c) 1988-1999 Amiga, Inc.
-
- Executables based on this information may be used in software
- for Amiga computers. All other rights reserved.
-
- This information is provided "as is"; no warranties are made.
- All use is at your own risk, and no liability or responsibility is assumed.
-
-
- ;=============================================================
- ; makefile - requires Manx 3.6
- ;=============================================================
- ;
- ;joymouse: joymouse.o32 iefa.o
- ; ln joymouse.o32 iefa.o -lc32 -o joymouse
- ;
- ;joymouse.o32: joymouse.c
- ; cc +L +C +D +p -B -S -L100 -o joymouse.o32 joymouse.c
- ;
- ;iefa.o: iefa.asm
- ; as -o iefa.o iefa.asm
- ;
- ;=============================================================
- ; joymouse.c
- ;=============================================================
- ;
- #define DEBUG
- #include "exec/types.h"
- #include "exec/nodes.h"
- #include "exec/lists.h"
- #include "exec/ports.h"
- #include "exec/interrupts.h"
- #include "devices/gameport.h"
- #include "devices/input.h"
- #include "devices/inputevent.h"
- #include "libraries/dos.h"
-
- struct Task *FindTask();
-
- struct MsgPort iorp = {
- {0, 0, NT_MSGPORT, 0, 0}, 0, SIGF_SINGLE, 0, {0, 0, 0, 0, 0}
- };
-
- struct IOStdReq ior = {
- {{0, 0, NT_MESSAGE, 0, 0}, &iorp, 0},
- 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- struct InputEvent nullEvent = {
- NULL, IECLASS_NULL
- };
-
- struct GamePortTrigger joyTrigger = {
- GPTF_DOWNKEYS|GPTF_UPKEYS, 1, 1, 1
- };
-
- struct GamePortTrigger mouseTrigger = {
- GPTF_DOWNKEYS|GPTF_UPKEYS, 0, 1, 1
- };
-
- extern VOID eventAFunction();
-
- struct Interrupt inputHandler = {
- {0, 0, NT_INTERRUPT, 100, 0}, 0, eventAFunction
- };
-
- #define MAXDELTA 255
- #define DELTASHIFT 4
-
- int deltaX = 0;
- int deltaY = 0;
-
- struct InputEvent *
- eventFunction(event, data)
- struct InputEvent *event;
- {
- struct InputEvent *loopevent;
-
- #ifdef DEBUG
- kprintf(".");
- #endif
-
- loopevent = event;
- do {
- if (loopevent->ie_Class == IECLASS_RAWMOUSE) {
- /* handle X, then Y. slow down faster than speed up */
- /* this could use another iteration to get it to "feel" right */
- if (loopevent->ie_X < 0) {
- #ifdef DEBUG
- kprintf("<");
- #endif
- if (deltaX <= 0) {
- if (deltaX > -MAXDELTA) deltaX--;
- }
- else deltaX = deltaX/2;
- }
- else if (loopevent->ie_X > 0) {
- #ifdef DEBUG
-
- kprintf(">");
- #endif
- if (deltaX >= 0) {
- if (deltaX < MAXDELTA) deltaX++;
- }
- else deltaX = deltaX/2;
- }
- else if (loopevent->ie_Y != 0) {
- if (deltaX != 0) deltaX += (deltaX<0)?1:-1;
- }
- else deltaX = deltaX/2;
- if (deltaX < 0)
- loopevent->ie_X = (deltaX-((1<<DELTASHIFT)+1))>>DELTASHIFT;
- else
- loopevent->ie_X = (deltaX+((1<<DELTASHIFT)-1))>>DELTASHIFT;
-
- if (loopevent->ie_Y < 0) {
- #ifdef DEBUG
- kprintf("v");
- #endif
- if (deltaY <= 0) {
- if (deltaY > -MAXDELTA) deltaY--;
- }
- else deltaY = deltaY/2;
- }
- else if (loopevent->ie_Y > 0) {
- #ifdef DEBUG
- kprintf("^");
- #endif
- if (deltaY >= 0) {
- if (deltaY < MAXDELTA) deltaY++;
- }
- else deltaY = deltaY/2;
- }
- else if (loopevent->ie_X != 0) {
- if (deltaY != 0) deltaY += (deltaY<0)?1:-1;
- }
- else deltaY = deltaY/2;
- if (deltaY < 0)
- loopevent->ie_Y = (deltaY-((1<<DELTASHIFT)+1))>>DELTASHIFT;
- else
- loopevent->ie_Y = (deltaY+((1<<DELTASHIFT)-1))>>DELTASHIFT;
- }
- }
- while ((loopevent = loopevent->ie_NextEvent) != 0);
- return(event);
- }
-
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- char c;
- int result;
-
- NewList(&iorp.mp_MsgList);
- iorp.mp_SigTask = (struct Task *) FindTask((char *) NULL);
-
- if (OpenDevice("input.device", 0, &ior, 0)) exit(20);
-
- /* free this controller */
- c = GPCT_NOCONTROLLER;
- ior.io_Command = IND_SETMTYPE;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- DoIO(&ior);
-
- /* wait for the SETM to take effect with a side effect */
- ior.io_Command = IND_WRITEEVENT;
- ior.io_Length = (LONG) sizeof(nullEvent);
- ior.io_Data = (APTR) &nullEvent;
- DoIO(&ior);
-
- /* switch to the right game port */
- c = 1;
- ior.io_Command = IND_SETMPORT;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- DoIO(&ior);
-
- /* set this controller to a joystick */
- c = GPCT_ABSJOYSTICK;
- ior.io_Command = IND_SETMTYPE;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- DoIO(&ior);
-
- /* set the trigger for the joystick */
- ior.io_Command = IND_SETMTRIG;
- ior.io_Length = (LONG) sizeof(joyTrigger);
- ior.io_Data = (APTR) &joyTrigger;
- DoIO(&ior);
-
- /* insert the accellerator handler into the food chain */
- ior.io_Command = IND_ADDHANDLER;
- ior.io_Data = (APTR) &inputHandler;
- ior.io_Length = (LONG) sizeof(struct Interrupt);
- DoIO(&ior);
-
- /* wait for this program to terminate */
- Wait(SIGBREAKF_CTRL_C);
-
- /* free this controller */
- c = GPCT_NOCONTROLLER;
- ior.io_Command = IND_SETMTYPE;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- DoIO(&ior);
-
- /* remove the accellerator handler from the food chain */
- ior.io_Command = IND_REMHANDLER;
- ior.io_Data = (APTR) &inputHandler;
- ior.io_Length = (LONG) sizeof(struct Interrupt);
- DoIO(&ior);
-
- /* switch to the left game port */
- c = 0;
- ior.io_Command = IND_SETMPORT;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- result = DoIO(&ior);
-
- /* set the trigger for a mouse */
- ior.io_Command = IND_SETMTRIG;
- ior.io_Length = sizeof(mouseTrigger);
- ior.io_Data = (APTR) &mouseTrigger;
- DoIO(&ior);
-
- /* set this controller to a mouse */
- c = GPCT_MOUSE;
- ior.io_Command = IND_SETMTYPE;
- ior.io_Length = 1;
- ior.io_Data = (APTR) &c;
- result = DoIO(&ior);
- }
-
- ;=============================================================
- ; iefa.asm
- ;=============================================================
- ;
- ; Copyright (c) 1988-1999 Amiga, Inc.
- ;
- ; Executables based on this information may be used in software
- ; for Amiga computers. All other rights reserved.
- ;
- ; This information is provided "as is"; no warranties are made.
- ; All use is at your own risk, and no liability or responsibility is assumed.
- ;
- XREF _eventFunction
-
- XDEF _eventAFunction
- _eventAFunction:
- MOVEM.L A0/A1,-(A7)
- JSR _eventFunction
- ADDQ.L #8,A7
- RTS
-
- END
-
-
- /******************************************************************************
- *
- * Source Control
- * --------------
- * $Header: propjoy.c,v 34.1 85/11/24 17:59:44 bart Exp $
- *
- * $Locker: $
- *
- * $Log: propjoy.c,v $
- * Revision 34.1 85/11/24 17:59:44 bart
- * be system compatible
- *
- * Revision 34.0 86/11/21 16:35:51 bart
- * added to rcs for updating
- *
- * Copyright (c) 1988-1999 Amiga, Inc.
- *
- * Executables based on this information may be used in software
- * for Amiga computers. All other rights reserved.
- *
- * This information is provided "as is"; no warranties are made.
- * All use is at your own risk, and no liability or responsibility is assumed.
- *
- ******************************************************************************/
-
- /* main.c - test program for add/rem tof task - bart - 05.19.86 */
- /* propjoy.c modified program for proportional controller - bart - 11.21.86 */
-
- ;=============================================================
- ; propjoy.c
- ;=============================================================
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/execbase.h>
- #include <exec/execname.h>
-
- #include <graphics/gfxbase.h>
- #include <graphics/graphint.h>
-
- #include <hardware/cia.h>
- #include <hardware/custom.h>
- #include <hardware/intbits.h>
-
- #include <resources/potgo.h>
-
- #define V1_POINT_2 33
-
- #define NUM_SERVERS 2
-
- #define MAX_COUNT (UWORD)~1 /* do it for a while */
-
- /* use system defined hard addresses */
-
- extern struct Custom custom;
-
- /* use system defined addresses for potgo and pot1dat */
-
- #define POTGO &custom.potgo
- #define POT0DAT &custom.pot0dat
- #define POT1DAT &custom.pot1dat
-
- /* vertical blank interrupt server priority */
-
- #define HIGHINTPRI 127L /* needs to be replaced with priority relative */
- #define LOWINTPRI -127L /* needs to be replaced with priority relative */
-
- /* bit number defines for potgo ... */
-
- #define START_B 0
-
- #define DATRX_B 8
- #define DATRY_B 10
-
- #define DATLX_B 12
- #define DATLY_B 14
-
- /* masks ... */
-
- #define START_F (1L << START_B)
- #define DATRX_F (1L << DATRX_B)
- #define DATRY_F (1L << DATRY_B)
- #define DATLX_F (1L << DATLX_B)
- #define DATLY_F (1L << DATLY_B)
-
- #define RPOTX (START_F | DATRX_F)
- #define RPOTY (START_F | DATRY_F)
- #define RPOTXY (START_F | DATRX_F | DATRY_F)
-
- #define LPOTX (START_F | DATLX_F)
- #define LPOTY (START_F | DATLY_F)
- #define LPOTXY (START_F | DATLX_F | DATLY_F)
-
- struct ExecBase *ExecBase = NULL;
- struct GfxBase *GfxBase = NULL;
- struct PotgoBase *PotgoBase = NULL;
-
- /* global storage for potdat */
-
- UWORD oldbits = NULL;
- UWORD potbits = NULL;
- ULONG potdat = NULL;
-
- /* create server-task to read the proportional joysticks,*/
- /* update potdat, and then poke potgo to start next data read */
-
- /* reserve space for the interrupt servers */
- struct Isrvstr server[NUM_SERVERS] = {NULL};
-
- first_server(i)
- int i;
- {
- /* read previous proportional joystick values */
- potdat = *(ULONG *)POT0DAT;
-
- /* poke potgo, restore old bits */
- WritePotgo(oldbits,((~1)<<8)|oldbits);
-
- /* be nice -- let other servers run, too */
- return(NULL);
- }
-
- second_server(i)
- int i;
- {
- /* poke potgo, start prop joystick read */
- WritePotgo(potbits,((~1)<<8)|potbits);
-
- /* be nice -- let other servers run, too */
- return(NULL);
- }
-
-
- main()
- {
- LONG error = FALSE;
- struct Isrvstr *iserver[NUM_SERVERS];
- LONG i;
-
- /* set server priorities */
- server[0].is_Node.ln_Pri = HIGHINTPRI;
- server[1].is_Node.ln_Pri = LOWINTPRI;
-
- /* set up server pointers */
- iserver[0] = &server[0];
- iserver[1] = &server[1];
-
- if((ExecBase = (struct ExecBase *)OpenLibrary(EXECNAME,V1_POINT_2)) != NULL)
- {
- if((GfxBase = (struct GfxBase *)
- OpenLibrary("graphics.library",V1_POINT_2)) != NULL)
- {
-
- if((PotgoBase = OpenResource(POTGONAME,V1_POINT_2)) != NULL)
- {
-
- /* remember currently used bits */
- oldbits = ~(AllocPotBits(~1));
-
- /* restore previous state of bit allocation */
- FreePotBits(~oldbits);
-
- /* now attempt to allocate start potbit */
- potbits = AllocPotBits(START_F);
-
- Forbid();
-
- /* add interrupt servers */
-
- AddTOF(iserver[0],first_server,0);
-
- AddTOF(iserver[1],second_server,1);
-
- Permit();
-
- /* loop until done */
-
- for(i=0; i < MAX_COUNT; i++)
- {
- /* wait for server to update pot values */
- WaitTOF();
-
- /* only output information once every second */
- if(!(i % ExecBase->VBlankFrequency))
- {
- }
- }
-
- Forbid();
-
- for(i=0; i < NUM_SERVERS; i++)
- {
- RemTOF(iserver[i]);
- }
-
- Permit();
-
- /* free potbits */
-
- FreePotBits(potbits);
-
- CloseLibrary(GfxBase);
- }
- else
- {
- error = TRUE;
- }
- }
- else
- {
- error = TRUE;
- }
-
- CloseLibrary(ExecBase);
-
- }
- else
- {
- error = TRUE;
- }
-
- /* return error code */
- exit(error);
- }
-